package com.hp.bon.logreverse.perf;

import com.hp.bon.sgw.util.Comutils;
import com.hp.ocs.diameter.DiameterUtils;
import com.hp.ocs.diameter.message.Message;
import com.hp.ocs.diameter.node.Capability;
import com.hp.ocs.diameter.node.NodeManager;
import com.hp.ocs.diameter.node.NodeSettings;
import com.hp.ocs.diameter.node.NotARequestException;
import com.hp.ocs.diameter.node.Peer;
import com.hp.ocs.diameter.node.PeerFactory;
import com.hp.ocs.diameter.node.StaleConnectionException;
import com.hp.ocs.utils.DeamonApplicationHelper;
import java.io.PrintStream;
import java.net.URI;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.StringTokenizer;
import java.util.logging.Level;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import org.slf4j.LoggerFactory;

@Path("/")
public class SimpleDCCServer
{
  private static final org.slf4j.Logger _log = LoggerFactory.getLogger(SimpleDCCServer.class);
  private static String SERVER_HOSTID = "SR@001.ctnbc-bon.net";
  private static String SERVER_REALM = "001.ctnbc-bon.net";
  private static String SERVER_IP = "0.0.0.0";
  private static int SERVER_PORT = 3870;
  private Map<String, String> params = null;
  private NodeManager dccNode;
  String manualSendHostID = null;

  public static void main(String[] args)
    throws Exception
  {
    Map<String,String> params = Comutils.parseArgs(args);
    for (Entry entry : params.entrySet()) {
      System.out.println(" key " + (String)entry.getKey() + " value:" + 
        (String)entry.getValue());
    }
    SimpleDCCServer server = new SimpleDCCServer(params);
    server.start();
  }

  public SimpleDCCServer(Map<String, String> params) {
    this.params = params;
  }
  public SimpleDCCServer() {
    this.params = new HashMap();
  }
  @GET
  @Path("connect/hostId/{host}/{port}")
  @Produces({"text/plain"})
  public String connectNode(@PathParam("hostId") String hostID, @PathParam("host") String host, @PathParam("port") String port) {
    String serverURI = "aaa://" + host + ":" + port;
    try {
      URI uri = new URI(serverURI);
      Peer severPeer = PeerFactory.getInstance().getPeerServer(hostID, 
        hostID.substring(hostID.indexOf('@') + 1), uri);
      this.dccNode.addPersistentPeer(severPeer);

      return "success";
    } catch (Exception e) {
      e.printStackTrace();
      return "error:" + e.toString();
    }
  }

  public void start() throws Exception {
    if (this.params.get("hostID") != null) {
      SERVER_HOSTID = (String)this.params.get("hostID");
      SERVER_REALM = SERVER_HOSTID.substring(SERVER_HOSTID.indexOf('@') + 1);
    }
    _log.info("Load paramter:hostID=" + SERVER_HOSTID);

    if (this.params.get("ip") != null) {
      SERVER_IP = (String)this.params.get("ip");
    }
    _log.info("Load paramter:ip=" + SERVER_IP);

    if (this.params.get("port") != null) {
      SERVER_PORT = Integer.parseInt((String)this.params.get("port"));
    }
    _log.info("Load paramter:port=" + SERVER_PORT);

    NodeSettings settings = loadConfiguration();
    if (settings == null) {
      System.exit(-1);
    }
    this.dccNode = new NodeManager(settings);
    this.dccNode.setRetransmitParameter(0, 60000);
    this.dccNode.useThreadPool(5, 100, 300, 2000);
    this.dccNode.setConnectionTimeout(3, 3600L, 36000L);
    this.dccNode.setTcpBuffer(DiameterUtils.getCapacityBytes("1000KB", -1), 
      DiameterUtils.getCapacityBytes("1000KB", -1));
    this.dccNode.setConnectionTimeout(3, 60L, 0L);
    this.dccNode.start();

    String persistPeerStr = (String)this.params.get("persistPeer");
    if (persistPeerStr != null)
    {
      _log.info(addPersistPeer(persistPeerStr));
    }
  }

  public void stop()
  {
    this.dccNode.stop();
  }

  private NodeSettings loadConfiguration() {
    _log.info("Load confirguration...");
    try {
      Capability capability = new Capability();
      StringTokenizer st = new StringTokenizer("0,4", ",; ");
      while (st.hasMoreTokens()) {
        int id = Integer.parseInt(st.nextToken());
        capability.addAuthApp(id);
        _log.info("Support AuthApp:" + id);
      }
      st = new StringTokenizer("0,4", ",; ");
      while (st.hasMoreTokens()) {
        int id = Integer.parseInt(st.nextToken());
        capability.addAcctApp(id);
        _log.info("Support AcctApp:" + id);
      }

      while (st.hasMoreTokens()) {
        int id = Integer.parseInt(st.nextToken());
        int app = Integer.parseInt(st.nextToken());
        capability.addVendorAuthApp(id, app);
        _log.info("Support vendor " + id + " authApp:" + app);
      }
      while (st.hasMoreTokens()) {
        int id = Integer.parseInt(st.nextToken());
        int app = Integer.parseInt(st.nextToken());
        capability.addVendorAcctApp(id, app);
        _log.info("Support vendor " + id + " acctApp:" + app);
      }

      String host = SERVER_HOSTID;
      int port = SERVER_PORT;
      return new NodeSettings(host, SERVER_REALM, 
        81000, capability, SERVER_IP, port, 
        "HP Simulator V0.1 (WangBo/bow@hp.com)", 16777216);
    }
    catch (Exception e) {
      e.printStackTrace();
    }
    return null;
  }

  public void sendRequest(Message request, Peer target)
  {
    try {
      this.dccNode.sendRequest(request, target, null);
    }
    catch (StaleConnectionException e) {
      e.printStackTrace();
    }
    catch (NotARequestException e) {
      e.printStackTrace();
    }
  }

  public Peer getActivePeer(String hostID) { Peer target = null;
    if (hostID != null)
    {
      this.manualSendHostID = hostID;
    }
    for (Peer peer : this.dccNode.getActivePeers())
    {
      if (this.manualSendHostID == null)
      {
        target = peer;
        break;
      }
      if (peer.hostID().equalsIgnoreCase(this.manualSendHostID)) {
        target = peer;
        break;
      }
    }
    if (this.dccNode.isPeerReady(target)) {
      return target;
    }

    return null;
  }

  private String addPersistPeer(String persistPeerStr)
  {
    String[] str1s = persistPeerStr.split("#");
    StringBuilder sb = new StringBuilder();
    for (String peerStr : str1s)
    {
      String[] strs = peerStr.split(";");
      if (strs.length != 3) return "strs.length != 3";
      String result = connectNode(strs[0], strs[1], strs[2]);
      if (sb.length() > 0)
      {
        sb.append("#");
      }
      sb.append(result);
    }

    return sb.toString();
  }
  public static boolean setLogLevel(String logName, Level level) {
    java.util.logging.Logger _logger = java.util.logging.Logger.getLogger(logName);
    _logger.setLevel(level);
    DeamonApplicationHelper.resetLogerLevel4JDK(_logger);
    return true;
  }
}